<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * SimplyPost
 *
 * @author		Pascal Kriete
 * @package		SimplyPost
 * @copyright	Copyright (c) 2008, Pascal Kriete
 * @license 	http://www.gnu.org/licenses/lgpl.txt
 */

// ------------------------------------------------------------------------

/**
 * SimplyPost Template Parser
 *
 * @package		SimplyPost
 * @subpackage	Libraries
 * @category	Templates
 * @author		Pascal Kriete
 */

class SP_Parser extends CI_Parser {
	
	var $_ci_key;
	var $_CI;
	
	/**
	 * Parse a template
	 *
	 * @access	public
	 */
	function parse($file, $data = array(), $return = FALSE)
	{
		$this->_CI =& get_instance();
		
		// Get template file
		$path = TMPPATH.TEMPLATE.$file.EXT;
		$template = file_get_contents($path);
				
		// Blank, don't bother
		if ($template == '')
		{
			return FALSE;
		}
		
		$template = $this->_parse($template, $data);
		
		// Return if it was asked for
		if ($return == FALSE)
		{
			$this->_CI->output->append_output($template);			
		}
		else
		{			
			return $template;
		}		
	}

	// --------------------------------------------------------------------
	
	/**
	 * Parsing function that does the actual work
	 *
	 * @access	public
	 * @param	type	description
	 * @return	description
	 */
	function _parse($template, $data = array())
	{
		$this->_CI =& get_instance();
		
		if (!is_array($data))
			$data = array();
		
		//Start off by flattening the whole thing
		$template = $this->_parse_nested($template, $data);
		
		//Now check if we _must_ do any php includes
		$template = $this->_parse_includes($template, $data);
		
		// Include Global Variable Tags
		include (APPPATH.'views/tags/var'.EXT);

		// Parse Variable Tags
		foreach($tags as $sp_key => $sp_single)
		{
			$template = $this->_parse_single('var:'.$sp_key, $sp_single, $template);
		}
		
		unset($tags);
		
		// Include Conditional Tags
		include (APPPATH.'views/tags/cond'.EXT);
		
		// Parse Conditional Tags
		foreach($tags as $sp_key => $sp_double)
		{
			$template = $this->_parse_conditional('cond:'.$sp_key, $sp_double, $template);
		}
		
		unset($tags);
	
		// Parse variables that were passed as array
		foreach ($data as $key => $val)
		{
			if (is_array($val))
			{
				$template = $this->_parse_pair($key, $val, $template);		
			}
			else
			{
				$template = $this->_parse_single($key, (string)$val, $template);
			}
		}
		
		// Parse if's
		$template = $this->_parse_ifs($template);
		
		// Parse style-sheets and javascript
		$template = $this->_parse_styles($template);
		$template = $this->_parse_js($template);
		
		// Parse anchor tags
		$template = $this->_parse_anchors($template);
		
		// Parse form tags
		$template = $this->_parse_forms($template);
		
		return $template;
	}
	
	// --------------------------------------------------------------------
	
	/**
	 *  Parse a tag pair
	 *
	 * Parses tag pairs:  {some_tag} string... {/some_tag}
	 *
	 * @access	private
	 * @param	string
	 * @param	array
	 * @param	string
	 * @return	string
	 */
	function _parse_pair($variable, $data, $string)
	{	
		if (FALSE === ($match = $this->_match_pair($string, $variable)))
		{
			return $string;
		}
		
		$str = '';
		foreach ($data as $row)
		{
			$temp = $match['1'];
			
			$temp = $this->_parse($temp, $row, TRUE);

			$str .= $temp;
		}
		
		return str_replace($match['0'], $str, $string);
	}

	// --------------------------------------------------------------------
	
	/**
	 * Parse Conditional Keys
	 *
	 * @access	private
	 */
	function _parse_conditional($key, $template, $text)
	{
		if ( ! preg_match_all("|{".$key."}(.+?){/".$key."}|s", $text, $match))
		{
			return $text;
		}

		if (isset($template[2]) && $template[2] == FALSE)
		{
			return str_replace($match['0'], '', $text);
		}
		
		$find = array('{'.$key.'}', '{/'.$key.'}');
		$start = $template[0];
		$stop = $template[1];
		
		$text = str_replace($find, array($start, $stop), $text);

		return $text;
	}

	// --------------------------------------------------------------------
	
	/**
	 * Parse Nested Template Tags (i.e. {nest:global/header} )
	 *
	 * @access	private
	 */
	function _parse_nested($text, $data)
	{
		preg_match_all('/{nest:(.+?)}/', $text, $matches);
		foreach($matches[0] as $key => $match)
		{
			$inner = $this->parse($matches[1][$key], $data, TRUE);
			$text = str_replace($match, $inner, $text);
		}
		
		return $text;
	}

	// --------------------------------------------------------------------
	
	/**
	 * Files where you cannot get around php (yet...use sparingly) (i.e. {include:global/js_vars} )
	 * These cannot be nested - it's a one time deal
	 *
	 * DEPRECATED!!!
	 *
	 * @access	private
	 */
	function _parse_includes($text, $data)
	{
		preg_match_all('/{include:(.+?)}/', $text, $matches);
		foreach($matches[0] as $key => $match)
		{
			$path = TMPPATH.TEMPLATE.$matches[1][$key].EXT;
			$inner = $this->_CI->load->file($path, $data, TRUE);
			$text = str_replace($match, $inner, $text);
		}
		return $text;
	}
		
	// --------------------------------------------------------------------
	
	/**
	 * Parses anchor tags (i.e. {anchor:'home', 'Forum Home'} )
	 *
	 *
	 * @access	private
	 */
	function _parse_anchors($text)
	{
		$q = '(?:\'|")';
		$optional = '(?:, '.$q.'(.+?)'.$q.')?';
		preg_match_all('/{anchor:'.$q.'(.+?)'.$q.', '.$q.'(.+?)'.$q.$optional.'}/', $text, $matches);

		foreach($matches[0] as $key => $match)
		{
			$inner = anchor($matches[1][$key], $matches[2][$key], $matches[3][$key]);
			$text = str_replace($match, $inner, $text);
		}
		
		return $text;
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Parses form tags (i.e. {form:'controller/function'} and {/form} )
	 *
	 *
	 * @access	private
	 */
	function _parse_forms($text)
	{
		$q = '(?:\'|")';
		preg_match_all('/{form:'.$q.'(.+?)'.$q.'}/', $text, $matches);
		foreach($matches[0] as $key => $match)
		{
			$inner = form_open($matches[1][$key]);
			$text = str_replace($match, $inner, $text);
		}
		
		$text = str_replace('{/form}', '</form>', $text);
		
		return $text;
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Parses style-sheet tags (i.e. {style-sheet:folder/name.css} )
	 *
	 * @access	private
	 */
	function _parse_styles($text)
	{	
		preg_match_all('/{style-sheet:(.+?)}/', $text, $matches);
		foreach($matches[0] as $key => $match)
		{
			$inner = '<link rel="stylesheet" href="'.base_url().'css/'.$matches[1][$key].'" type="text/css" media="screen" charset="utf-8">';
			$text = str_replace($match, $inner, $text);
		}
		
		return $text;
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Parses javascript tags (i.e. {javascript:folder/name.js} )
	 *
	 * @access	private
	 */
	function _parse_js($text)
	{
		preg_match_all('/{javascript:(.+?)}/', $text, $matches);
		foreach($matches[0] as $key => $match)
		{
			$inner = '<script src="'.base_url().'js/'.$matches[1][$key].'" type="text/javascript" charset="utf-8"></script>';
			$text = str_replace($match, $inner, $text);
		}
		
		return $text;
	}
		
	// --------------------------------------------------------------------
	
	/**
	 * Parses if statements !DO NOT NEST! ({if:cond} ... {else} ... {/endif})
	 *
	 * @access	private
	 */
	function _parse_ifs($text)
	{
		preg_match_all("#{if:(.+?)}(.+?){/endif}#s", $text, $matches);
		
		foreach($matches[0] as $key => $match)
		{
			eval('$inner = ('.$matches[1][$key].' ? TRUE : FALSE );');

			$parts = explode('{else}', $matches[2][$key]);

			if ($inner) {
				$text = str_replace($match, $parts[0], $text);
			}
			else {
				if (count($parts) > 1)
					$text = str_replace($match, $parts[1], $text);
				else
					$text = str_replace($match, '', $text);
			}
		}
		
		return $text;
	}

}

/* If I ever decide to support it */

/* PHP PARSING ON */
/*
// Assign variables to view
foreach (get_object_vars($this->_CI) as $_ci_key => $_ci_var)
{
	if ( ! isset($this->$_ci_key))
	{
		$this->$_ci_key =& $this->_CI->$_ci_key;
	}
}

// Eval and capture the result
ob_start();
echo eval('?>'.$template.'<?php ');
$template = ob_get_contents();
@ob_end_clean();
*/


?>